# coding: utf-8
import threading
import tap_config
from sys_utils import LOG

class PortTraffic(object):
    '''
    端口流量统计信息，包括去往不同出口的流量信息
    toport_traffics用于保存所有去往不同出口
    '''
    def __init__(self, id, traffic):
        self.port_id = id
        self.port_traffic = traffic
        self.toward_portstats = []

    # 添加出端口流量信息
    def add_portstat(self, stat):
        self.toward_portstats.append(stat)

    # 移除出端口流量信息
    def remove_portstat(self, stat):
        self.toward_portstats.remove(stat)

class PhysicalPort(object):
    '''
    物理端口，包括48个千兆口和4个万兆口
    物理端口的基本信息：
    * ID —— 标识符
    * NAME —— 名称
    * ALIAS —— 别名（如果没有设置别名，则默认为名称）
    * FLAG —— 是否需要进行TAP（默认不需要）
    '''
    def __init__(self, id, name, alias = None, flag = False):
        self.port_id = id
        self.port_name = name
        if alias:
            self.port_alias = alias
        else:
            self.port_alias = name
        self.tap_flag = flag

    # 设置物理端口别名
    def set_alias(self, alias):
        if alias:
            self.port_alias = alias
            LOG("alias physical port, port_id = " + str(self.port_id))

    # 使能TAP功能
    def enable_tap(self):
        self.tap_flag = True
        LOG("enable_tap physical port, port_id = " + str(self.port_id))

    # 失效TAP功能
    def disable_tap(self):
        self.tap_flag = False
        LOG("disable_tap physical port, port_id = " + str(self.port_id))

class LagPort(object):
    '''
    LAG端口，通过将多个端口进行汇聚，生成新的虚拟端口
    '''
    def __init__(self, id, name, alias = None):
        self.port_id = id
        self.port_name = name
        if alias:
            self.port_alias = alias
        else:
            self.port_alias = name
        self.include_ports = []

    # 设置LAG端口别名
    def set_alias(self, alias):
        if alias:
            self.port_alias = alias
            LOG("alias lag port, port_id = " + str(self.port_id))

    # 设置包含端口
    def set_includeports(self, ports):
        self.include_ports = ports
        LOG("set lag include_ports")

    # 添加包含端口
    def add_includeport(self, port):
        self.include_ports.append(port)
        LOG("add to lagport ports where port_id = " + str(port))

    # 移除包含端口
    def remove_includeport(self, port):
        self.include_ports.remove(port)
        LOG("remove from lagport ports where port_id = " + str(port))

class LogicGroup(object):
    '''
    逻辑组，可以将多个端口加入到一个逻辑组
    对于逻辑组，有如下功能：
    * 对逻辑组的操作，适用于其下所有包含端口
    * ID —— 逻辑组标识符（唯一性）
    * NAME —— 逻辑组名称
    * ALIAS —— 逻辑组别名
    * INCLUDE_PORTS —— 包含的端口信息
    '''
    def __init__(self, id, name, alias):
        self.lg_id = id
        self.lg_name = name
        if alias:
            self.lg_alias = alias
        else:
            self.lg_alias = name
        self.include_ports = []

    # 设置逻辑组别名
    def set_alias(self, alias):
        if not alias:
            self.lg_alias = alias
            LOG("alias logic group, lg_id = " + str(self.lg_id))

    # 设置包含端口
    def set_includeports(self, ports):
        self.include_ports = ports
        LOG("set logicgroup include_ports")

    # 添加包含端口
    def add_includeport(self, port):
        self.include_ports.append(port)
        LOG("add to logicgroup ports where port_id = " + str(port))

    # 移除包含端口
    def remove_includeport(self, port):
        self.include_ports.remove(port)
        LOG("remove from logicgroup ports where port_id = " + str(port))

class GroupTable(object):
    '''
    用于表示一个组表信息
    '''
    def __init__(self, id, type):
        self.gt_id = id
        self.gt_type = type
        self.gt_bucket = []

    def add_action(self, action):
        self.gt_bucket.append(action)
        LOG("add to gt_bucket where action = " + action)

    def remove_action(self, action):
        self.gt_bucket.remove(action)
        LOG("remove from gt_bucket where action = " + action)

class Controller(object):
    '''
    控制器信息
    '''
    def __init__(self, name, ip, port):
        self.ctl_name = name
        self.ctl_ip = ip
        self.ctrl_port = port

class FlowTraffic(object):
    '''
    基于流的流量统计信息，通过采样进行速率计算
    '''
    def __init__(self, id, bytes, packets, speed):
        self.flow_id = id
        self.bytes = bytes
        self.packets = packets
        self.speed = speed

class BoundFixedQueue(object):
    '''
    有界固定队列，超容量时自动丢弃最老对象
    '''
    def __init__(self):
        self.queue = []

    # 添加元素，如果容量超标，则先弹出最先插入的元素，再添加元素
    def offer(self, entry):
        print "!!!!before queue size is ", len(self.queue)
        self.queue.append(entry)
        print "!!!!after queue size is ", len(self.queue)

    # 获取队列中最后一个元素
    def get_last(self):
        print "!!!!queue's get last, queue's size is ", len(self.queue)
        print "!!!!queue", type(self.queue[-1]), " ", self.queue[-1]['flow_bytes']
        return self.queue[-1]

    # 返回元素列表
    def dump(self):
        return self.queue

    # 清空元素信息
    def clear(self):
        self.queue = []

class FlowEntry(object):
    '''
    用于配置OpenFlow流表项
    '''
    def __init__(self):
        self.traffic_set = BoundFixedQueue()
        self.table_id = 0
        self.duration = 0

    '''
    def set_priority(self, prio = 0):
        self.priority = prio

    def set_in_port(self, inport = -1):
        self.in_port = inport

    def set_dl_vlan(self, dlvlan = -1):
        self.dl_vlan = dlvlan

    def set_dl_src(self, dlsrc = None):
        self.dl_src = dlsrc

    def set_dl_dst(self, dldst = None):
        self.dl_dst = dldst

    def set_dl_type(self, dltype = None):
        self.dl_type = dltype

    def set_nw_src(self, nwsrc = None):
        self.nw_src = nwsrc

    def set_nw_dst(self, nwdst = None):
        self.nw_dst = nwdst

    def set_nw_tos(self, nwtos = None):
        self.nw_tos = nwtos

    def set_nw_proto(self, nwproto = None):
        self.nw_proto = nwproto

    def set_tp_src(self, tpsrc = None):
        self.tp_src = tpsrc

    def set_tp_dst(self, tpdst = None):
        self.tp_dst = tpdst
    '''

    def set_flow_id(self, flowid = 0):
        self.flow_id = flowid

    def set_table(self, table = 0):
        self.table_id = table

    def set_duration(self, duration = 0):
        self.duration = duration

    def set_match_fields(self, match = None):
        self.match_fields = match

    def set_actions(self, actions = None):
        self.actions = actions

    # 向流表项添加流量统计信息
    def offer_flow_traffic(self, traffic):
        self.traffic_set.offer(traffic)

    # 获取流量统计最后一个元素
    def last_flow_traffic(self):
        return self.traffic_set.get_last()

    # 获取当前所有流量统计信息
    def dump_flow_traffics(self):
        return self.traffic_set.dump()

    # 清空当前所有流量统计信息
    def clear_flow_traffics(self):
        self.traffic_set.clear()

class MainDataContainer(object) :

    def __init__(self):
        # 互斥锁
        self.lock = threading.Lock()

        # 交换机所有端口信息
        self.port_map = {}
        # 交换机的物理端口信息集合
        self.phy_port_map = {}
        # 交换机的LAG端口信息集合
        self.lag_port_map = {}
        # 交换机的逻辑组信息集合
        self.logic_group_map = {}
        # 交换机的流表信息集合
        self.flow_entry_map = {}
        # 交换机的组表信息集合
        self.group_table_map = {}

        # 交换机的监控流表项ID集合
        self.monitored_flow_list = []

    '''
    物理端口的增删改查
    '''
    def add_phyport(self, id, name, alias = None, flag = False) :
        phy_port = PhysicalPort(id, name, alias, flag)
        self.phy_port_map[id] = phy_port
        self.port_map[id] = phy_port
        LOG("add physical port, port_id = " + str(id))

    def del_phyport(self, id) :
        if self.phy_port_map.has_key(id) :
            self.phy_port_map.pop(id)
            self.port_map.pop(id)
            LOG("delete physical port, port_id = " + str(id))

    def set_phyport_alias(self, id, alias = None):
        if self.phy_port_map.has_key(id) :
            target_port = self.phy_port_map.get(id)
            target_port.set_alias(alias)

    def set_phyport_tap(self, id, flag = False):
        if self.phy_port_map.has_key(id):
            target_port = self.phy_port_map.get(id)
            if flag:
                target_port.enable_tap()
            else:
                target_port.disable_tap()

    def get_phyport(self, id):
        return self.phy_port_map.get(id)

    def get_phyports(self):
        return self.phy_port_map.values()

    '''
    LAG端口的增删改查
    '''
    def add_lagport(self, id, name, alias = None):
        print 'ADD_LAG_PORT = ', alias
        lag_port = LagPort(id, name, alias)
        self.lag_port_map[id] = lag_port
        self.port_map[id] = lag_port
        LOG("add lag port, port_id = " + str(id))

    def del_lagport(self, id):
        if self.lag_port_map.has_key(id):
            self.lag_port_map.pop(id)
            self.port_map.pop(id)
            LOG("delete lag port, port_id = " + str(id))

    def set_lagport_alias(self, id, alias = None):
        if self.lag_port_map.has_key(id) :
            target_port = self.lag_port_map.get(id)
            target_port.set_alias(alias)

    def set_lagport_inports(self, id, portarr):
        if self.lag_port_map.has_key(id):
            target_port = self.lag_port_map.get(id)
            if portarr:
                target_port.set_includeports(portarr)

    def get_lagport(self, id):
        return self.lag_port_map.get(id)

    def get_lagports(self):
        return self.lag_port_map.values()

    '''
    逻辑组的增删改查
    '''
    def add_logicgroup(self, id, name, alias):
        logic_group = LogicGroup(id, name, alias)
        self.logic_group_map[id] = logic_group
        LOG("add logic group, lg_id = " + str(id))

    def del_logicgroup(self, id):
        if self.logic_group_map.has_key(id):
            self.logic_group_map.pop(id)
            LOG("delete logic group, lg_id = " + str(id))

    def set_logicgroup_alias(self, id, alias = None):
        if self.logic_group_map.has_key(id) :
            target_logic_group = self.logic_group_map.get(id)
            target_logic_group.set_alias(alias)

    def set_logicgroup_inports(self, id, portarr):
        if self.logic_group_map.has_key(id):
            target_logic_group = self.logic_group_map.get(id)
            if portarr:
                target_logic_group.set_includeports(portarr)

    def get_logicgroup(self, id):
        return self.logic_group_map.get(id)

    def get_logicgroups(self):
        return self.logic_group_map.values()

    '''
    流表的增删查改
    '''
    def add_flowentry(self, id, entry):
        entry.set_flow_id(id)
        self.flow_entry_map[id] = entry

    def del_flowentry(self, id):
        if self.flow_entry_map.has_key(id):
            self.flow_entry_map.pop(id)

    def set_flowentry(self, id, new_entry):
        self.flow_entry_map[id] = new_entry

    def get_flowentry(self, id):
        return self.flow_entry_map.get(id)

    def get_flowentries(self):
        return self.flow_entry_map.values()

    '''
    组表的增删查改
    '''
    def add_grouptable(self, id, type):
        group_table = GroupTable(id, type)
        self.group_table_map[id] = group_table
        LOG("add group table, table_id = " + str(id))

    def del_grouptable(self, id):
        if self.group_table_map.has_key(id):
            self.group_table_map.pop(id)
            LOG("delete group table, table_id = " + str(id))

    def set_grouptable_type(self, id, type):
        if self.group_table_map.has_key(id):
            target_grouptable = self.group_table_map.get(id)
            target_grouptable.set_type(type)

    def set_grouptable_bucket(self, id, bucket):
        if self.group_table_map.has_key(id):
            target_grouptable = self.group_table_map.get(id)
            if bucket:
                for action in bucket:
                    target_grouptable.add_action(action)

    def get_grouptable(self, id):
        return self.group_table_map.get(id)

    def get_grouptables(self):
        return self.group_table_map.values()

    '''
    监控流表项的注册与注销
    '''
    def register_monitor_flowentry(self, id):
        if id not in self.monitored_flow_list:
            self.monitored_flow_list.append(id)
            LOG("register monitor flowentry where id = " + str(id))

    def unregister_monitor_flowentry(self, id):
        if id in self.monitored_flow_list:
            self.monitored_flow_list.remove(id)
            LOG("unregister monitor flowentry where id = " + str(id))

    def offer_flow_traffic(self, id, flow_traffic):
        self.flow_entry_map.get(id).offer_flow_traffic(flow_traffic)

    def fecth_flow_traffics(self, id):
        return self.flow_entry_map.get(id).dump_flow_traffics()

    def get_monitored_flowentries(self):
        return self.monitored_flow_list

    '''
    设置控制器
    '''
    def set_controller(self, name, ip, port):
        self.controller = Controller(name, ip, port)